package com.cgs.query.service.impl

import com.cgs.query.config.JpaCustomProperties
import com.cgs.query.config.JpaCustomPropertiesAware
import com.cgs.query.config.RunnerJdbcTemplateAware
import com.cgs.query.connection.ConnectionFactory
import com.cgs.query.connection.DefaultConnectionFactory
import com.cgs.query.domain.QuerySource
import com.cgs.query.event.QuerySourceEvent
import com.cgs.query.exception.QueryException
import com.cgs.query.handler.*
import com.cgs.query.service.IQueryProjectService
import com.cgs.query.service.IQuerySourceService
import com.cgs.query.service.jpa.QuerySourceRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.ApplicationEventPublisher
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageRequest
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.jdbc.core.RowMapper
import org.springframework.stereotype.Service
import java.sql.Connection

@Service
open class QuerySourceServiceImpl : IQuerySourceService, UserInfoHolderAware, SecurityAdapter, RunnerJdbcTemplateAware, JpaCustomPropertiesAware {

    private lateinit var userHolder: UserInfoHolder

    private lateinit var jdbcTemplate: JdbcTemplate

    private lateinit var jpaCustomProperties: JpaCustomProperties
    @Autowired
    private lateinit var publisher: ApplicationEventPublisher
    @Autowired
    private lateinit var repository: QuerySourceRepository
    @Autowired
    private lateinit var queryProjectService: IQueryProjectService

    override fun findById(id: String): QuerySource? = repository.findOne(id)

    @Permission
    override fun save(source: QuerySource): QuerySource {
        return repository.save(source.apply { if (userId.isNullOrBlank()) userId = userHolder.getUserId() }.apply {
            if (source.id.isNotBlank()) {
                publisher.publishEvent(QuerySourceEvent(source.id, QuerySourceEvent.Type.UPDATE).let {
                    it.originQuerySource = repository.findOne(source.id)
                    it.newQuerySource = this@apply
                    return@let it
                })
            }
        })
    }

    override fun exist(source: QuerySource): Boolean {
        TODO()
    }

    override fun delete(id: String) {
        val projects = queryProjectService.findBySourceId(id)
        if (projects == null || projects.isEmpty()) {
            repository.delete(id)
            publisher.publishEvent(QuerySourceEvent(id, QuerySourceEvent.Type.DELETE))
        } else {
            throw QueryException("存在项目：${projects.joinToString(",") { it.name }}")
        }
    }

    override fun findAll(): List<QuerySource>? = repository.findAll()

    override fun findAll(pn: Int, ps: Int): Page<QuerySource>? = repository.findAll(PageRequest(pn, ps))

    override fun findByUnLock(projectName: String?): List<QuerySource>? {
        return if(projectName.isNullOrBlank()){
             repository.findByUnLock()
        }else{
            repository.findByUnLockAndProjectName(projectName)
        }
    }

    override fun findByProjectName(projectName: String) = repository.findByProjectName(projectName)

    override fun findSourceIdByDefineNameAndProjectName(defineName: String, projectName: String): String? {
        return jdbcTemplate.queryForObject(jpaCustomProperties.findSourceIdByDefineNameAndProjectName, RowMapper<String> { rs, _ ->
            if (rs != null) {
                for (i in 1..2) {
                    if (rs.getString(i).isNotBlank()) {
                        return@RowMapper rs.getString(i)
                    }
                }
            }
            return@RowMapper null
        }, defineName, projectName)
    }

    override fun findSourceIdByDefineNameAndTagNameAndProjectName(defineName: String, tagName: String, projectName: String): String? {
        return jdbcTemplate.queryForObject(jpaCustomProperties.findSourceIdByDefineNameAndTagNameAndProjectName, RowMapper<String> { rs, _ ->
            if (rs != null) {
                for (i in 1..3) {
                    if (rs.getString(i).isNotBlank()) {
                        return@RowMapper rs.getString(i)
                    }
                }
            }
            return@RowMapper null
        }, defineName, tagName, projectName)
    }

    override fun findSourceIdByDefineNameAndAliasAndProjectName(defineName: String, alias: String, projectName: String): String? {
        val findSourceIdPODtoByDefineNameAndAliasAndProjectName = repository.findSourceIdPODtoByDefineNameAndAliasAndProjectName(defineName, alias, projectName)
        return findSourceIdPODtoByDefineNameAndAliasAndProjectName?.getSourceId()
    }

    override fun adapter(methodName: String, args: Array<Any?>): PermissionObject? {
        return when (methodName) {
            "save" -> {
                val querySource = (args[0] as QuerySource)
                PermissionObject(null).apply {
                    this.userId = querySource.userId
                    this.obj = querySource
                    this.type = "querySource"
                }
            }
            else -> null
        }
    }

    override fun setUserInfoHolder(userInfoHolder: UserInfoHolder) {
        userHolder = userInfoHolder
    }

    override fun setRunnerJdbcTemplate(jdbcTemplate: JdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate
    }

    override fun setJpaCustomProperties(jpaCustomProperties: JpaCustomProperties) {
        this.jpaCustomProperties = jpaCustomProperties
    }

}

fun QuerySource.jdbcEquals(querySource: QuerySource?): Boolean {
    return querySource != null && this.url == querySource.url && this.userName == querySource.userName
            && this.password == querySource.password
}